package com.uci.scheduleshare.calendardb;

import java.util.ArrayList;
import java.util.Calendar;
import java.util.List;
import java.util.regex.Pattern;

import com.uci.scheduleshare.calendar.Contact;
import com.uci.scheduleshare.calendar.Event;
import com.uci.scheduleshare.utils.JulianDay;

import android.content.ContentResolver;
import android.content.ContentUris;
import android.content.Context;
import android.database.Cursor;
import android.net.Uri;
import android.provider.CalendarContract.Calendars;
import android.provider.CalendarContract.Events;
import android.provider.CalendarContract.Instances;
import android.util.Patterns;

/**
 * CS 190 Spring 2012
 * CalendarDBAdapter.java
 * An adapter class that retrieves data from the Android device
 * via CalendarProvider API
 * @author Patrick Hsu, Lauren Ko, Pomi Park
 *
 */
public class CalendarDBAdapter {
	public static final String[] CALENDAR_PROJECTION = new String[] {
			Calendars._ID, 						// 0
			Calendars.ACCOUNT_NAME, 			// 1
			Calendars.CALENDAR_DISPLAY_NAME, 	// 2
	};

	private static final int CAL_ID_INDEX = 0;
	private static final int CAL_ACCOUNT_NAME_INDEX = 1;
	private static final int CAL_DISPLAY_NAME_INDEX = 2;

	public static final String[] EVENT_PROJECTION = new String[] { 
			Events._ID, 						// 0
			Events.TITLE, 						// 1
	};
	private static final int EVENT_ID_INDEX = 0;
	private static final int EVENT_TITLE_INDEX = 1;
	
	public static final String[] INSTANCE_PROJECTION = new String[] { 
		Instances._ID, 							// 0
		Instances.START_DAY,					// 1
		Instances.START_MINUTE,					// 2
		Instances.END_DAY,						// 3
		Instances.END_MINUTE					// 4
	};
	private static final int INST_ID_INDEX = 0;
	private static final int INST_START_DAY_INDEX = 1;
	private static final int INST_START_MIN_INDEX = 2;
	private static final int INST_END_DAY_INDEX = 3;
	private static final int INST_END_MIN_INDEX = 4;

	private Context context;

	/**
	 * CalendarDBAdapter constructor
	 * @param c
	 */
	public CalendarDBAdapter(Context c) {
		context = c;
	}

	/**
	 * Get all the calendars associated with a user
	 * @param username
	 * @return
	 */
	public List<String[]> getCalendars(String username) {
		List<String[]> calendarNames = new ArrayList<String[]>();
		Cursor cursor = null;
		ContentResolver cr = context.getContentResolver();
		Uri uri = Calendars.CONTENT_URI;
		String selection = "(" + Calendars.ACCOUNT_NAME + " = ?)";
		String[] selectionArgs = new String[] { username };
		cursor = cr.query(uri, CALENDAR_PROJECTION, selection, selectionArgs,
				null);
		if (cursor.getCount() > 0) {
			while (cursor.moveToNext()) {
				calendarNames.add(new String[] {
						cursor.getString(CAL_ID_INDEX),
						cursor.getString(CAL_ACCOUNT_NAME_INDEX),
						cursor.getString(CAL_DISPLAY_NAME_INDEX) });
			}
		}
		cursor.close();
		return calendarNames;
	}
	
	/**
	 * Create a contact for the user based on the calendar id passed 
	 * in the parameters
	 * @param calendarID
	 * @return a Contact
	 */
	public Contact createContact(String calendarID) {
		Cursor cursor = null;
		String username = "";
		String calendarname = "";
		ContentResolver cr = context.getContentResolver();
		Uri uri = Calendars.CONTENT_URI;
		String selection = "(" + Calendars._ID + " = ?)";
		String[] selectionArgs = new String[] { calendarID };
		cursor = cr.query(uri, CALENDAR_PROJECTION, selection, selectionArgs,
				null);
		if (cursor.getCount() > 0) {
			while (cursor.moveToNext()) {
				username = cursor.getString(CAL_ACCOUNT_NAME_INDEX);				
				calendarname = cursor.getString(CAL_DISPLAY_NAME_INDEX);
			}
		}
		cursor.close();
		List<Event> myEvents = createEvents(calendarID);
		return new Contact(username, calendarname, 0, myEvents, 0x800000FF, true);
	}
	
	/**
	 * Get the names and ids of all the Calendars in the Android device
	 * @return a List of String[]
	 */
	public List<String[]> getAllCalendarNames() {
		List<String[]> results = new ArrayList<String[]>();
		Cursor cursor = null;
		ContentResolver cr = context.getContentResolver();
		Uri uri = Calendars.CONTENT_URI;
		cursor = cr.query(uri, CALENDAR_PROJECTION, null, null,
				null);
		if (cursor.getCount() > 0) {
			
			String[] calendarNamesArray = new String[cursor.getCount()];
			String[] calendarIDArray = new String[cursor.getCount()];
			int i = 0;
			while (cursor.moveToNext()) {
				calendarNamesArray[i] = cursor.getString(CAL_DISPLAY_NAME_INDEX);
				calendarIDArray[i] = cursor.getString(CAL_ID_INDEX);
				i++;
				//Log.d("text", calendarNamesArray[i]);
			}
			results.add(calendarNamesArray);
			results.add(calendarIDArray);
		}
		cursor.close();
		return results;
	}

	/**
	 * Get all the events associated to a calendar id
	 * @param calendarID
	 * @return a list of String[]
	 */
	public List<String[]> getEvents(String calendarID) {
		List<String[]> events = new ArrayList<String[]>();
		Cursor cursor = null;
		ContentResolver cr = context.getContentResolver();
		Uri uri = Events.CONTENT_URI;
		String selection = "(" + Events.CALENDAR_ID + " = ?)";
		String[] selectionArgs = new String[] { calendarID };
		cursor = cr
				.query(uri, EVENT_PROJECTION, selection, selectionArgs, null);
		if (cursor.getCount() > 0) {
			while (cursor.moveToNext()) {
				events.add(new String[] {
						cursor.getString(EVENT_ID_INDEX),
						cursor.getString(EVENT_TITLE_INDEX) });
			}
		}
		cursor.close();
		return events;
	}
	
	/**
	 * Get all the instances related to an event
	 * @param eventID
	 * @return a List of String[]
	 */
	public List<String[]> getInstances(String eventID) {
		List<String[]> instances = new ArrayList<String[]>();
		Cursor cursor = null;
		ContentResolver cr = context.getContentResolver();
		Uri.Builder builder = Instances.CONTENT_URI.buildUpon();
		
		Calendar beginTime = Calendar.getInstance();
		beginTime.set(Calendar.DAY_OF_WEEK, Calendar.SUNDAY);
		beginTime.set(Calendar.HOUR_OF_DAY, 0);
		beginTime.set(Calendar.MINUTE, 0);
		long startMillis = beginTime.getTimeInMillis();
 
		Calendar endTime = Calendar.getInstance();
		endTime.set(Calendar.DAY_OF_WEEK, Calendar.SATURDAY);
		endTime.set(Calendar.HOUR_OF_DAY, 23);
		endTime.set(Calendar.MINUTE, 59);

		long endMillis = endTime.getTimeInMillis();
		
		// Get all the events between start (this week Sunday) and end (this week Saturday)
	    ContentUris.appendId(builder, startMillis);
	    ContentUris.appendId(builder, endMillis);
	    
		String selection = "(" + Instances.EVENT_ID + " = ?)";
		String[] selectionArgs = new String[] { eventID };
		cursor = cr
				.query(builder.build(), INSTANCE_PROJECTION, selection, selectionArgs, null);
		if (cursor.getCount() > 0) {
			while (cursor.moveToNext()) {
				instances.add(new String[] {
						cursor.getString(INST_ID_INDEX),
						cursor.getString(INST_START_DAY_INDEX),
						cursor.getString(INST_START_MIN_INDEX),
						cursor.getString(INST_END_DAY_INDEX),
						cursor.getString(INST_END_MIN_INDEX)});
			}
		}
		cursor.close();
		return instances;
	}
	
	/**
	 * Create all the events related to a calendar
	 * @param calendarID
	 * @return a List of Events
	 */
	public List<Event> createEvents(String calendarID) {
		List<Event> events = new ArrayList<Event>();

		List<String[]> mEvents = getEvents(calendarID); // Each event of the default calendar
		for(String[] e : mEvents) {
			List<String[]> mInstances = getInstances(e[EVENT_ID_INDEX]); // Each instance of that event
			for (String[] i : mInstances) {
				Event event = new Event(
						e[EVENT_TITLE_INDEX], 
						JulianDay.toDayNumber(i[INST_START_DAY_INDEX]), 
						Integer.parseInt(i[INST_START_MIN_INDEX]), 
						JulianDay.toDayNumber(i[INST_END_DAY_INDEX]), 
						Integer.parseInt(i[INST_END_MIN_INDEX]) );
				events.add(event);
			}
		}
		return events;
	}

}
